#pragma once

#ifndef _CORE_ANSWER_DATABASE_H_
#define _CORE_ANSWER_DATABASE_H_

#include "Core\Definations.h"
#include "Core\QuestionAndAnswer.h"

#include "Poco\Data\Session.h"
#include "Poco\SharedPtr.h"

namespace ExamSystem
{
    using Poco::Data::Session;
    using Poco::SharedPtr;
    /**************************************************************************\
     Component:     CAnswerDatabase
     Description:
        This class provides interface for accessing answer database.
    \**************************************************************************/
    class CAnswerDatabase
    {
    public:
        CAnswerDatabase(void);
        ~CAnswerDatabase(void);

    public:
        // open the database file
        bool Initialize(const std::string &databaseFile);
        bool IsInitialized(void) const;

        void Finalize(void);

        // create a new database
        bool CreateDatabase(const std::string &databaseFile, ExamInformation &info);

        // merge another database with this one
        bool MergeDatabase(const std::string &fileName);

        // get/save exam information from database
        bool LoadExamInformation(ExamInformation &info);
        bool SaveExamInformation(ExamInformation &info);

        // get all students who take part in the exam, as well as their total scores
        bool LoadStudents(std::vector<StudentInfo> &students, std::vector<double> &scores);

        // get question information (types and ids) for a student
        //bool LoadQuestions(const StudentInfo &student, std::vector<SharedPtr<CQuestion> > &questions);

        // get question ids by type
        bool LoadQuestions(QuestionType questionType, std::vector<int> &questionIDs);
        // get question ids by type for a student
        bool LoadQuestions(const StudentInfo &student, QuestionType questionType, std::vector<int> &questionIDs);
        bool LoadQuestions(const StudentInfo &student, QuestionType questionType, std::vector<int> &questionIDs, std::vector<double> &scores);

        // get answers for a student
        //bool LoadAnswers(const StudentInfo &student, std::vector<SharedPtr<CAnswer> > &answers);

        // get answers by type for a student
        //bool LoadAnswers(const StudentInfo &student, QuestionType questionType, std::vector<SharedPtr<CAnswer> > &answers);

        // get an answer by question type and id
        // we don't alloc the CAnswer instance here, which the call should do.
        // the caller should also set the questionID
        bool LoadAnswer(const StudentInfo &student, CAnswer *answer);

        // save an answer
        bool SaveAnswer(const StudentInfo &student, CAnswer *answer);

    protected:
        bool UpdateStatus(unsigned int nMask);
        bool CheckAnswerExist(const StudentInfo &student, CAnswer *answer, std::string &idx, double &score);
        void UpdateStudentScore(const StudentInfo &student, double oldScore, double newScore);

    protected:
        // answer getters
        bool LoadChoiceAnswer(const StudentInfo &student, CAnswer *answer);
        bool LoadFillingAnswer(const StudentInfo &student, CAnswer *answer);
        bool LoadTypingAnswer(const StudentInfo &student, CAnswer *answer);
        bool LoadQNAAnswer(const StudentInfo &student, CAnswer *answer);
        bool LoadOfficeAnswer(const StudentInfo &student, CAnswer *answer);
        bool LoadCodingAnswer(const StudentInfo &student, CAnswer *answer);
        bool LoadHtmlAnswer(const StudentInfo &student, CAnswer *answer);
        bool LoadPhotoshopAnswer(const StudentInfo &student, CAnswer *answer);

        // common type
        bool LoadFiledAnswer(const StudentInfo &student, CAnswer *answer);
        bool SaveFiledAnswer(const StudentInfo &student, CAnswer *answer);
        bool LoadPropertyAnswer(const StudentInfo &student, CAnswer *answer);
        bool SavePropertyAnswer(const StudentInfo &student, CAnswer *answer);

        // answer savers
        bool SaveChoiceAnswer(const StudentInfo &student, CAnswer *answer);
        bool SaveFillingAnswer(const StudentInfo &student, CAnswer *answer);
        bool SaveTypingAnswer(const StudentInfo &student, CAnswer *answer);
        bool SaveQNAAnswer(const StudentInfo &student, CAnswer *answer);
        bool SaveOfficeAnswer(const StudentInfo &student, CAnswer *answer);
        bool SaveCodingAnswer(const StudentInfo &student, CAnswer *answer);
        bool SaveHtmlAnswer(const StudentInfo &student, CAnswer *answer);
        bool SavePhotoshopAnswer(const StudentInfo &student, CAnswer *answer);

    protected:
        std::string m_databaseFile;
        SharedPtr<Session> m_session;
        std::vector<std::string> m_tableColumns[QuestionTypeCount + 1];
        bool m_flagInitialized;

        typedef bool (CAnswerDatabase::*AnswerLoader)(const StudentInfo &, CAnswer *);
        typedef bool (CAnswerDatabase::*AnswerSaver)(const StudentInfo &, CAnswer *);
        static AnswerLoader ms_answerLoaders[QuestionTypeCount];
        static AnswerSaver ms_answerSavers[QuestionTypeCount];

    public:
        static const std::string ms_answerTables[QuestionTypeCount + 2];
    };
}

#endif